home *** CD-ROM | disk | FTP | other *** search
- /*
- ** $Id: main.c,v 38.1 94/02/17 14:13:56 kcd Exp $
- ** $State: Exp $
- ** $Revision: 38.1 $
- ** $Date: 94/02/17 14:13:56 $
- ** $Author: kcd $
- **
- ** Amiga SANA-II SLIP device driver.
- **
- ** (C) Copyright 1992-1998 Amiga, Inc.
- **
- ** OwnDevUnit support added by Christopher A. Wichura.
- */
-
- #include "slip_device.h"
-
- #include <dos/dostags.h>
- #include <dos/rdargs.h>
-
- #include <clib/exec_protos.h>
- #include <clib/dos_protos.h>
- #include <clib/utility_protos.h>
- #include <clib/timer_protos.h>
- #include <clib/alib_stdio_protos.h>
- #include <clib/intuition_protos.h>
-
- #include <pragmas/exec_pragmas.h>
- #include <pragmas/dos_pragmas.h>
- #include <pragmas/utility_pragmas.h>
- #include <pragmas/timer_pragmas.h>
- #include <pragmas/intuition_pragmas.h>
-
- #include <string.h>
-
- #ifndef _GENPROTO
- #include "main_protos.h"
- #include "slcompress_protos.h"
- #endif
-
- /*
- ** To Do:
- **
- ** Try using an address field size of 0.
- **
- ** For speed purposes:
- **
- ** Downcode the packet encode/decode routines.
- */
-
- /*
- ** External variables and functions
- **
- */
-
- extern struct Library *ExtDeviceBase;
- extern VOID (*DevProcEntry)();
- extern ULONG IPToNum(STRPTR ipstr);
-
- /*
- ** Device Open vector
- **
- ** a1 - SANA2 IO Request
- ** a6 - Pointer to our device base
- ** d0 - Unit number
- ** d1 - Flags
- **
- */
-
- ULONG ASM DevOpen(REG(a1) struct IOSana2Req *ios2,
- REG(d0) ULONG s2unit,
- REG(d1) ULONG s2flags,
- REG(a6) struct SLIPDevice *slipDevice)
- {
- struct SLIPUnit *slipUnit;
- struct TagItem *bufftag;
- struct Library *UtilityBase;
- struct BufferManagement *bm;
- ULONG returncode;
- BOOL status = FALSE;
-
- slipDevice->sd_Device.lib_OpenCnt++; /* So we won't expunge ourselves... */
-
- /* Make sure our open remains single-threaded. */
- ObtainSemaphore(&slipDevice->sd_Lock); /* Enforce single threading since we may need to
- Wait() when starting up the Unit process */
-
- if(s2unit < SD_MAXUNITS) /* Legal Unit? */
- {
- if(slipUnit = InitSLIPUnit(s2unit,slipDevice)) /* Initialize the Unit */
- {
- if(UtilityBase = OpenLibrary("utility.library",37L)) /* For Tag functions */
- {
- /* Allocate a structure to store the pointers to the callback routines. */
-
- if(bm = AllocMem(sizeof(struct BufferManagement),MEMF_CLEAR|MEMF_PUBLIC))
- {
- /* Note: I don't complain if I can't find pointers to the callback routines.
- This is because there are some programs that may need to open me, but
- will never use any device commands that require the callbacks. */
-
- if(bufftag = FindTagItem(S2_CopyToBuff, (struct TagItem *)ios2->ios2_BufferManagement))
- {
- bm->bm_CopyToBuffer = (SANA2_CTB) bufftag->ti_Data;
- }
-
- if(bufftag = FindTagItem(S2_CopyFromBuff, (struct TagItem *)ios2->ios2_BufferManagement))
- {
- bm->bm_CopyFromBuffer = (SANA2_CFB) bufftag->ti_Data;
- }
-
- /* New SANA-II V2 Addition */
- if(bufftag = FindTagItem(S2_PacketFilter, (struct TagItem *)ios2->ios2_BufferManagement))
- {
- bm->bm_PacketFilterHook = (struct Hook *) bufftag->ti_Data;
- }
- else /* For backwards compatibility */
- {
- bm->bm_PacketFilterHook = &slipDevice->sd_DummyPFHook;
- }
-
- /* Init the list for CMD_READ requests */
-
- NewList((struct List *)&bm->bm_RxQueue);
-
- AddTail((struct List *)&slipUnit->su_BuffMgmt,(struct Node *)bm);
-
- /* Everything went okay. */
- status = TRUE;
- returncode = 0;
- slipDevice->sd_Device.lib_OpenCnt++;
- slipDevice->sd_Device.lib_Flags &=~LIBF_DELEXP;
- slipUnit->su_Unit.unit_OpenCnt++;
-
- /* Fix up the initial io request */
- ios2->ios2_BufferManagement = (void *)bm;
- ios2->ios2_Req.io_Error = 0;
- ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
- ios2->ios2_Req.io_Unit = (struct Unit *)slipUnit;
- ios2->ios2_Req.io_Device = (struct Device *)slipDevice;
- }
- CloseLibrary(UtilityBase);
- }
- }
- }
- /* See if something went wrong. */
- if(!status)
- {
- ios2->ios2_Req.io_Error = IOERR_OPENFAIL;
- ios2->ios2_Req.io_Unit = (struct Unit *) -1;
- ios2->ios2_Req.io_Device = (struct Device *) -1;
- returncode = IOERR_OPENFAIL;
- }
- ReleaseSemaphore(&slipDevice->sd_Lock);
- slipDevice->sd_Device.lib_OpenCnt--;
-
- return(returncode);
- }
-
- /*
- ** Device Close vector.
- **
- ** a1 - IOReq
- ** a6 - Device Pointer
- **
- */
-
- BPTR ASM DevClose(REG(a1) struct IOSana2Req *ios2,
- REG(a6) struct SLIPDevice *slipDevice)
- {
- struct SLIPUnit *slipUnit;
- BPTR seglist = 0L;
-
- ObtainSemaphore(&slipDevice->sd_Lock);
-
- slipUnit = (struct SLIPUnit *)ios2->ios2_Req.io_Unit;
-
- /* Trash the io_Device and io_Unit fields so that any attempt to use this
- request will die immediatly. */
-
- ios2->ios2_Req.io_Device = (struct Device *) -1;
- ios2->ios2_Req.io_Unit = (struct Unit *) -1;
-
- /* I always shut the unit process down if the open count drops to zero.
- That way, if I need to expunge, I never have to Wait(). */
-
- slipUnit->su_Unit.unit_OpenCnt--;
- if(!slipUnit->su_Unit.unit_OpenCnt)
- {
- ExpungeUnit(slipUnit,slipDevice);
- }
-
- slipDevice->sd_Device.lib_OpenCnt--;
-
- ReleaseSemaphore(&slipDevice->sd_Lock);
-
- /* Check to see if we've been asked to expunge. */
- if(slipDevice->sd_Device.lib_Flags & LIBF_DELEXP)
- seglist = DevExpunge(slipDevice);
-
- return(seglist);
- }
-
-
- /*
- ** Device Expunge vector
- **
- ** a6 - Device base
- **
- ** Note: You may NEVER EVER Wait() in expunge. Period.
- ** Don't even *think* about it.
- */
-
- BPTR ASM DevExpunge(REG(a6) struct SLIPDevice *slipDevice)
- {
- BPTR seglist;
- ULONG devbase;
- LONG devbasesize;
-
- if(slipDevice->sd_Device.lib_OpenCnt)
- {
- /* Sorry, we're busy. We'll expunge later on
- if we can. */
- slipDevice->sd_Device.lib_Flags |= LIBF_DELEXP;
- seglist = (BPTR)0L;
- }
- else
- {
- /* Free up our library base and function table after
- removing ourselves from the library list. */
- Remove((struct Node *)slipDevice);
- seglist = slipDevice->sd_SegList;
-
- devbase = (ULONG) slipDevice;
-
- devbasesize = (ULONG)slipDevice->sd_Device.lib_NegSize;
- devbase = devbase - devbasesize;
-
- devbasesize += (ULONG)slipDevice->sd_Device.lib_PosSize;
-
- FreeMem((APTR)devbase,devbasesize);
- }
- return(seglist);
- }
-
- /*
- ** InitSLIPUnit
- **
- ** Initialize (if needed) a new SLIP device Unit and process.
- **
- */
-
- struct SLIPUnit *InitSLIPUnit(ULONG s2unit,
- struct SLIPDevice *slipDevice)
- {
- struct SLIPUnit *slipUnit;
- struct TagItem NPTags[]={NP_Entry, 0, NP_Name, 0, NP_Priority, SLIP_PRI , TAG_DONE, 0};
- struct MsgPort *replyport;
-
- /* Check to see if the Unit is already up and running. If
- it is, just drop through. If not, try to start it up. */
-
- if(!slipDevice->sd_Units[s2unit])
- {
- /* Open up dos.library */
- if(slipDevice->sd_DOSBase = OpenLibrary("dos.library",37L))
- {
- /* Allocate a new Unit structure */
- if(slipUnit = AllocMem(sizeof(struct SLIPUnit), MEMF_CLEAR|MEMF_PUBLIC))
- {
- /* Do some initialization on the Unit structure */
-
- NewList(&slipUnit->su_Unit.unit_MsgPort.mp_MsgList);
-
- slipUnit->su_Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
- slipUnit->su_Unit.unit_MsgPort.mp_Flags = PA_IGNORE;
- slipUnit->su_Unit.unit_MsgPort.mp_Node.ln_Name = "slip.device";
-
- slipUnit->su_UnitNum = s2unit;
- slipUnit->su_Device = (struct Device *) slipDevice;
-
- NewList((struct List *)&slipUnit->su_Events);
- NewList((struct List *)&slipUnit->su_BuffMgmt);
- NewList((struct List *)&slipUnit->su_Track);
-
- #ifdef OWNDEVUNIT_SUPPORT
- sprintf(slipUnit->su_OwnerName, "slip.device unit %ld", s2unit);
- #endif
- /* Try to read in our configuration file */
- if(ReadConfig(slipUnit,slipDevice))
- {
- /* Start up the unit process */
- if(replyport = CreateMsgPort())
- {
- slipDevice->sd_Startup.Msg.mn_ReplyPort = replyport;
- slipDevice->sd_Startup.Device = (struct Device *) slipDevice;
- slipDevice->sd_Startup.Unit = (struct Unit *)slipUnit;
-
- NPTags[0].ti_Data = (ULONG) &DevProcEntry; /* Assembly entry point for the unit process. */
-
- /* Maybe this should be different for each unit? */
- NPTags[1].ti_Data = (ULONG) "slip.device"; /* Process name */
-
- ExtDeviceBase = (struct Library *)slipDevice;
-
- if(slipUnit->su_Proc = CreateNewProc(NPTags))
- {
- PutMsg(&slipUnit->su_Proc->pr_MsgPort,(struct Message *)&slipDevice->sd_Startup);
- WaitPort(replyport);
- GetMsg(replyport);
- }
- DeleteMsgPort(replyport);
- }
- }
- if(!slipUnit->su_Proc)
- {
- /* The Unit process couldn't start for some reason, so free the Unit structure. */
- FreeMem(slipUnit,sizeof(struct SLIPUnit));
- }
- else
- {
- /* Set up the Unit structure pointer in the device base */
- slipDevice->sd_Units[s2unit] = (struct Unit *)slipUnit;
- }
- }
- CloseLibrary(slipDevice->sd_DOSBase);
- }
- }
- return((struct SLIPUnit *)slipDevice->sd_Units[s2unit]);
- }
-
- /*
- **
- ** ExpungeUnit
- **
- ** Tells a unit process to go away...
- **
- ** This function is called from the DevClose routine when the open count for a
- ** unit reaches zero. This routine signals the unit process to exit and then
- ** waits for the unit process to acknowledge. The unit structure is then
- ** freed.
- */
-
- VOID ExpungeUnit(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- struct Task *unittask;
-
- unittask = (struct Task *)slipUnit->su_Proc;
-
- slipUnit->su_Proc = (struct Process *)FindTask(0L);
-
- Signal(unittask,SIGBREAKF_CTRL_F);
- Wait(SIGBREAKF_CTRL_F);
-
- slipDevice->sd_Units[slipUnit->su_UnitNum] = NULL;
-
- FreeMem(slipUnit, sizeof(struct SLIPUnit));
- }
-
- /*
- **
- ** ReadConfig
- **
- ** Attempt to read in and parse the driver's configuration file.
- **
- ** The files are named by ENV:SANA2/slipX.config where X is the decimal
- ** representation of the device's unit number.
- **
- */
-
- BOOL ReadConfig(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- UBYTE *linebuff,buff[40];
- STRPTR termchar;
- struct RDArgs *rdargs;
- BPTR ConfigFile;
- LONG args[11];
-
- BOOL status = FALSE;
- ULONG linenum=0;
-
- /* Create the name of our config file.. */
- sprintf(buff,"ENV:SANA2/slip%ld.config",(ULONG)slipUnit->su_UnitNum);
-
- /* ...and open it. */
- if(ConfigFile = Open(buff,MODE_OLDFILE))
- {
- /* Here, I use ReadArgs() to do the file parsing for me. */
-
- if(linebuff = AllocMem(256,MEMF_CLEAR|MEMF_PUBLIC))
- {
- if(rdargs = AllocDosObject(DOS_RDARGS, NULL))
- {
- while(FGets(ConfigFile, linebuff, 255))
- {
- linenum++;
- if(linebuff[0] == '#') /* Skip comment lines */
- continue;
-
- rdargs->RDA_Source.CS_Buffer = linebuff;
- rdargs->RDA_Source.CS_Length = 256;
- rdargs->RDA_Source.CS_CurChr = 0;
-
- /* ReadArgs() requires that the line be null-terminated
- or funny things happen. */
-
- termchar = (STRPTR) linebuff + strlen(linebuff);
- *termchar = '\n';
- termchar++;
- *termchar = 0;
-
- memset ((char *) args, 0, sizeof(args));
-
- /* Parse the line...*/
-
- if(ReadArgs("SERNAME/A,SERUNIT/A/N,SERBAUD/A/N,IPSTR/A,CD=CARRIERDETECT/S,7WIRE/S,COMP/S,AUTO/S,MTU/K/N,SERBUF/K/N,USEODU/S",args,rdargs))
- {
- strcpy(slipUnit->su_SerDevName,(STRPTR)args[0]);
- slipUnit->su_SerUnitNum = *((ULONG *)args[1]);
- slipUnit->su_BaudRate = *((ULONG *)args[2]);
- slipUnit->su_StAddr = 0;
- slipUnit->su_DefaultAddr = IPToNum((STRPTR)args[3]);
-
- if(args[4])
- slipUnit->su_State |= SLIPUF_CD;
- if(args[5])
- slipUnit->su_State |= SLIPUF_7WIRE;
- if(args[6])
- slipUnit->su_State |= SLIPUF_MAYCOMPRESS;
- if(args[7])
- slipUnit->su_State |= SLIPUF_AUTOCOMP;
- if(args[8])
- slipUnit->su_MTU = *((ULONG *)args[8]);
- else
- slipUnit->su_MTU = DEFAULT_SLIP_MTU;
- if(args[9])
- slipUnit->su_RBufLen = *((ULONG *)args[9]);
- else
- slipUnit->su_RBufLen = 16384L;
- #ifdef OWNDEVUNIT_SUPPORT
- if (args[10])
- slipUnit->su_ODUBase = OpenLibrary(ODU_NAME, 0L);
- else
- slipUnit->su_ODUBase = (struct Library *)NULL;
- #endif
- status = TRUE;
- FreeArgs(rdargs);
- break;
- }
- else
- {
- struct Library *IntuitionBase;
- struct EasyStruct es;
- if(IntuitionBase = OpenLibrary("intuition.library",37L))
- {
- es.es_StructSize=sizeof(struct EasyStruct);
- es.es_Flags=0;
- es.es_Title="Slip.device";
- es.es_TextFormat="Error in configuration file on line %ld.";
- es.es_GadgetFormat="Okay";
- EasyRequestArgs(NULL, &es, 0, &linenum);
- CloseLibrary(IntuitionBase);
- }
- break;
- }
-
- }
- FreeDosObject(DOS_RDARGS,rdargs);
- }
- FreeMem(linebuff, 256);
- }
- Close(ConfigFile);
- }
- return(status);
- }
-
-
- /*
- **
- ** BeginIO
- **
- ** This is the dispatch point for the driver's incoming IORequests.
- **
- ** Registers at entry:
- **
- ** a1 = IORequest
- ** a6 = Device Base
- **
- */
-
- #define SLIP_IMMEDIATES 0L
-
- VOID ASM DevBeginIO(REG(a1) struct IOSana2Req *ios2,
- REG(a6) struct SLIPDevice *slipDevice)
- {
- ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
-
- if(ios2->ios2_Req.io_Command < S2_END)
- {
- if((1L << ios2->ios2_Req.io_Command) & SLIP_IMMEDIATES)
- {
- PerformIO(ios2,slipDevice);
- }
- else
- {
- ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
- PutMsg((struct MsgPort *)ios2->ios2_Req.io_Unit,(struct Message *)ios2);
- }
- }
- else
- {
- ios2->ios2_Req.io_Error = IOERR_NOCMD;
- TermIO(ios2,slipDevice);
- }
- }
-
- /*
- ** This routine is used to dispatch an IO request either from BeginIO
- ** or from the Unit process.
- */
-
- VOID PerformIO(struct IOSana2Req *ios2,
- struct SLIPDevice *slipDevice)
- {
- struct SLIPUnit *slipUnit;
-
- slipUnit = (struct SLIPUnit *)ios2->ios2_Req.io_Unit;
-
- ios2->ios2_Req.io_Error = 0;
-
- switch(ios2->ios2_Req.io_Command)
- {
- case CMD_READ: ReadPacket(ios2,slipUnit,slipDevice);
- break;
-
- case CMD_WRITE: WritePacket(ios2,slipUnit,slipDevice);
- break;
-
- case S2_DEVICEQUERY: DeviceQuery(ios2,slipUnit,slipDevice);
- break;
-
- case S2_GETSTATIONADDRESS: GetStationAddress(ios2,slipUnit,slipDevice);
- break;
-
- case S2_CONFIGINTERFACE: ConfigInterface(ios2,slipUnit,slipDevice);
- break;
-
- /* These commands are not appropriate for SLIP/CSLIP */
- case S2_READORPHAN:
- case S2_ADDMULTICASTADDRESS:
- case S2_DELMULTICASTADDRESS:
- case S2_MULTICAST: ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- TermIO(ios2,slipDevice);
- break;
-
- case S2_BROADCAST: WritePacket(ios2,slipUnit,slipDevice);
- break;
-
- case S2_TRACKTYPE: TrackType(ios2,slipUnit,slipDevice);
- break;
-
- case S2_UNTRACKTYPE: UnTrackType(ios2,slipUnit,slipDevice);
- break;
-
- case S2_GETTYPESTATS: GetTypeStats(ios2,slipUnit,slipDevice);
- break;
-
- case S2_GETSPECIALSTATS: GetSpecialStats(ios2,slipUnit,slipDevice);
- break;
-
- case S2_GETGLOBALSTATS: GetGlobalStats(ios2,slipUnit,slipDevice);
- break;
-
- case S2_ONEVENT: OnEvent(ios2,slipUnit,slipDevice);
- break;
-
- case S2_ONLINE: Online(ios2,slipUnit,slipDevice);
- break;
-
- case S2_OFFLINE: Offline(ios2,slipUnit,slipDevice);
- break;
-
- default: ios2->ios2_Req.io_Error = IOERR_NOCMD;
- TermIO(ios2,slipDevice);
- break;
- }
- }
-
- /*
- ** This function returns any device specific statistics that
- ** we may have. Unfortunately, we don't have and SLIP specific
- ** statistics.
- */
- VOID ASM GetSpecialStats(STDSLIPARGS)
- {
- struct Sana2SpecialStatHeader *stats;
-
- stats = (struct Sana2SpecialStatHeader *)ios2->ios2_StatData;
-
- stats->RecordCountSupplied = 0;
- TermIO(ios2,slipDevice);
- }
-
- /*
- ** This function returns the global statistics for the
- ** slip device.
- */
- VOID ASM GetGlobalStats(STDSLIPARGS)
- {
- struct Sana2DeviceStats *stats;
-
- stats = (struct Sana2DeviceStats *)ios2->ios2_StatData;
-
- stats->PacketsReceived = slipUnit->su_Stats.PacketsReceived;
- stats->PacketsSent = slipUnit->su_Stats.PacketsSent;
- stats->BadData = slipUnit->su_Stats.BadData;
- stats->Overruns = slipUnit->su_Stats.Overruns;
- stats->UnknownTypesReceived = slipUnit->su_Stats.UnknownTypesReceived;
- stats->Reconfigurations = slipUnit->su_Stats.Reconfigurations;
- stats->LastStart.tv_secs = slipUnit->su_Stats.LastStart.tv_secs;
- stats->LastStart.tv_micro = slipUnit->su_Stats.LastStart.tv_micro;
-
- ios2->ios2_Req.io_Error = 0;
-
- TermIO(ios2,slipDevice);
- }
-
- /*
- ** This function returns statistics for a specific
- ** type of packet that is being tracked. Unfortunately,
- ** SLIP can't differentiate between different packet
- ** types, which makes packet type tracking essentially
- ** useless as the numbers would essentially be the same
- ** as those found via S2_GETGLOBALSTATS.
- **
- ** Just to be thourough, I have arbitrarily picked
- ** the packet type for SLIP IP packets to be 2048, the
- ** same as tha used for Ethernet. This will at least
- ** allow you to track IP packets.
- */
- VOID ASM GetTypeStats(STDSLIPARGS)
- {
- struct Sana2PacketTypeStats *stats;
- struct SuperS2PTStats *sstats;
-
- ObtainSemaphore(&slipUnit->su_ListLock);
-
- stats = (struct Sana2PacketTypeStats *)ios2->ios2_StatData;
- sstats = (struct SuperS2PTStats *)slipUnit->su_Track.mlh_Head;
-
- while(sstats->ss_Node.mln_Succ)
- {
- if(ios2->ios2_PacketType == sstats->ss_PType)
- {
- stats->PacketsSent = sstats->ss_Stats.PacketsSent;
- stats->PacketsReceived = sstats->ss_Stats.PacketsReceived;
- stats->BytesSent = sstats->ss_Stats.BytesSent;
- stats->BytesReceived = sstats->ss_Stats.BytesReceived;
- stats->PacketsDropped = sstats->ss_Stats.PacketsDropped;
- break;
- }
- sstats = (struct SuperS2PTStats *)sstats->ss_Node.mln_Succ;
- }
- ReleaseSemaphore(&slipUnit->su_ListLock);
- if(!sstats->ss_Node.mln_Succ)
- {
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_NOT_TRACKED;
- }
- TermIO(ios2,slipDevice);
- }
-
- /*
- ** This function adds a packet type to the list
- ** of those that are being tracked.
- */
- VOID ASM TrackType(STDSLIPARGS)
- {
- struct SuperS2PTStats *stats;
-
- ObtainSemaphore(&slipUnit->su_ListLock);
-
- stats = (struct SuperS2PTStats *)slipUnit->su_Track.mlh_Head;
-
- while(stats->ss_Node.mln_Succ)
- {
- if(ios2->ios2_PacketType == stats->ss_PType)
- {
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_ALREADY_TRACKED;
- break;
- }
- stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
- }
- if(!stats->ss_Node.mln_Succ)
- {
- if(stats = AllocMem(sizeof(struct SuperS2PTStats),MEMF_CLEAR|MEMF_PUBLIC))
- {
- stats->ss_PType = ios2->ios2_PacketType;
- if(ios2->ios2_PacketType == 2048)
- slipUnit->su_IPTrack = stats;
- AddTail((struct List *)&slipUnit->su_Track,(struct Node *)stats);
- }
- }
- ReleaseSemaphore(&slipUnit->su_ListLock);
-
- TermIO(ios2,slipDevice);
- }
-
- /*
- ** This function removes a packet type from the
- ** list of those that are being tracked.
- */
- VOID ASM UnTrackType(STDSLIPARGS)
- {
- struct SuperS2PTStats *stats;
- struct SuperS2PTStats *stats_next;
-
- ObtainSemaphore(&slipUnit->su_ListLock);
-
- stats = (struct SuperS2PTStats *)slipUnit->su_Track.mlh_Head;
-
- while(stats->ss_Node.mln_Succ)
- {
- stats_next = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
- if(ios2->ios2_PacketType == stats->ss_PType)
- {
- if(ios2->ios2_PacketType == 2048)
- slipUnit->su_IPTrack = NULL;
- Remove((struct Node *)stats);
- FreeMem(stats,sizeof(struct SuperS2PTStats));
- stats = NULL;
- break;
- }
- stats = stats_next;
- }
- if(stats)
- {
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_NOT_TRACKED;
- }
- ReleaseSemaphore(&slipUnit->su_ListLock);
-
- TermIO(ios2,slipDevice);
- }
-
- /*
- ** This function is called whenever we receive a packet
- ** from the serial device driver.
- **
- */
- VOID PacketReceived(ULONG length,
- struct SLIPUnit *slipUnit)
- {
- slipUnit->su_Stats.PacketsReceived++;
-
- if(slipUnit->su_IPTrack)
- {
- slipUnit->su_IPTrack->ss_Stats.PacketsReceived++;
- slipUnit->su_IPTrack->ss_Stats.BytesReceived+=length;
- }
- }
-
- /*
- ** This function is called whenever a packet is
- ** sent to the serial device driver.
- */
- VOID PacketSent(ULONG length,
- struct SLIPUnit *slipUnit)
- {
- slipUnit->su_Stats.PacketsSent++;
-
- if(slipUnit->su_IPTrack)
- {
- slipUnit->su_IPTrack->ss_Stats.PacketsSent++;
- slipUnit->su_IPTrack->ss_Stats.BytesSent+=length;
- }
- }
-
- /*
- ** This function is called whenever a packet that
- ** is too large is received.
- */
- VOID PacketOverrun(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- slipUnit->su_Stats.Overruns++;
- DoEvent(S2EVENT_ERROR|S2EVENT_RX,slipUnit,slipDevice);
- }
-
- /*
- ** This function is called whenever a packet with
- ** garbage data is encountered.
- */
- VOID ReceivedGarbage(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- slipUnit->su_Stats.BadData++;
- DoEvent(S2EVENT_ERROR|S2EVENT_RX,slipUnit,slipDevice);
- }
-
- /*
- ** This function is called whenever a packet
- ** is dropped by the SLIP driver.
- */
- VOID PacketDropped(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- if(slipUnit->su_IPTrack)
- {
- slipUnit->su_IPTrack->ss_Stats.PacketsDropped++;
- }
- DoEvent(S2EVENT_ERROR|S2EVENT_RX,slipUnit,slipDevice);
- }
-
- /*
- ** This function is used to return an IO request
- ** back to the sender.
- */
- VOID ASM TermIO(REG(a2) struct IOSana2Req *ios2,
- REG(a6) struct SLIPDevice *slipDevice)
- {
- if(!(ios2->ios2_Req.io_Flags & IOF_QUICK))
- ReplyMsg((struct Message *)ios2);
- }
-
- /*
- ** The device AbortIO() entry point.
- **
- ** A1 - The IO request to be aborted.
- ** A6 - The device base.
- */
- ULONG ASM DevAbortIO(REG(a1) struct IOSana2Req *ios2,
- REG(a6) struct SLIPDevice *slipDevice)
- {
- ULONG result = 0L;
- struct SLIPUnit *slipUnit;
- struct BufferManagement *bm;
-
- slipUnit = (struct SLIPUnit *)ios2->ios2_Req.io_Unit;
- ObtainSemaphore(&slipUnit->su_ListLock);
- if(ios2->ios2_Req.io_Message.mn_Node.ln_Type != NT_REPLYMSG)
- {
- switch(ios2->ios2_Req.io_Command)
- {
- /* Walk the list of BufferManagement structs, trying AbortReq()
- on each. */
-
- case CMD_READ: bm = (struct BufferManagement *)slipUnit->su_BuffMgmt.mlh_Head;
- while(bm->bm_Node.mln_Succ)
- {
- /* If result is 0, the IORequest was found,
- so we're done. */
- if(!(result=AbortReq(&bm->bm_RxQueue,ios2,slipDevice)))
- break;
-
- bm = (struct BufferManagement *)bm->bm_Node.mln_Succ;
- }
- break;
-
- case CMD_WRITE: Disable();
- if(!(result=AbortReq((struct MinList *)&slipUnit->su_Tx->mp_MsgList,ios2,slipDevice)))
- result=AbortReq((struct MinList *)&slipUnit->su_TxFast->mp_MsgList,ios2,slipDevice);
- Enable();
- break;
-
- case S2_ONEVENT: result=AbortReq(&slipUnit->su_Events,ios2,slipDevice);
- break;
-
- default: result=IOERR_NOCMD;
- break;
- }
- }
- ReleaseSemaphore(&slipUnit->su_ListLock);
- return(result);
- }
-
- /*
- ** This funcion is used to locate an IO request in a linked
- ** list and abort it if found.
- */
- ULONG AbortReq(struct MinList *minlist,
- struct IOSana2Req *ios2,
- struct SLIPDevice *slipDevice)
- {
- struct Node *node, *next;
- ULONG result=IOERR_NOCMD;
-
- node = (struct Node *)minlist->mlh_Head;
-
- while(node->ln_Succ)
- {
- next = node->ln_Succ;
-
- if(node == (struct Node *)ios2)
- {
- Remove((struct Node *)ios2);
- ios2->ios2_Req.io_Error = IOERR_ABORTED;
- TermIO(ios2,slipDevice);
- result = 0;
- break;
- }
- node = next;
- }
- return(result);
- }
-
- /*
- ** This function handles S2_CONFIGINTERFACE commands.
- */
- VOID ASM ConfigInterface(STDSLIPARGS)
- {
- /* Note: we may only be configured once. */
- if(!(slipUnit->su_State & SLIPUF_CONFIG))
- {
- if(OpenSerial(slipUnit,slipDevice))
- {
- /* FIXED - Now sets our address to whatever the
- protocol stack says to use. */
- CopyMem(&ios2->ios2_SrcAddr,&slipUnit->su_StAddr,4);
- slipUnit->su_State |= SLIPUF_CONFIG;
- }
- }
- else
- {
- /* Sorry, we're already configured. */
- ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
- ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
- }
- TermIO(ios2,slipDevice);
- }
-
- /*
- ** This function handles S2_GETSTATIONADDRESS commands.
- **
- ** We don't really have a hardware address, so we will
- ** just clear the source address field.
- */
-
- VOID ASM GetStationAddress(STDSLIPARGS)
- {
- UBYTE i;
-
- for(i=0; i< SANA2_MAX_ADDR_BYTES; i++)
- {
- ios2->ios2_SrcAddr[i]=0;
- ios2->ios2_DstAddr[i]=0;
- }
- CopyMem(&slipUnit->su_StAddr,&ios2->ios2_SrcAddr,4);
- CopyMem(&slipUnit->su_DefaultAddr,&ios2->ios2_DstAddr,4);
-
- TermIO(ios2,slipDevice);
- }
-
- /*
- ** Init Table for the Sana2DeviceQuery structure.
- */
-
- struct DQInfo DQTable[9] =
- {
- DQ_CLONG, 4, 0, /* This and the next are placeholders. */
- DQ_CLONG, 4, 0,
- DQ_CLONG, 4, 0,
- DQ_CLONG, 4, 0,
- DQ_CWORD, 2, 32,
- DQ_MTU, 4, 0,
- DQ_BPS, 4, 0,
- DQ_CLONG, 4, S2WireType_SLIP,
- 0, 0, 0
- };
-
- /*
- ** This function handles S2_DEVICEQUERY comands.
- */
- VOID ASM DeviceQuery(STDSLIPARGS)
- {
- ULONG size, supplied;
- UWORD i;
- UBYTE *w_byte;
- struct DQInfo *dqi;
-
- struct Sana2DeviceQuery *sdq;
-
- sdq = (struct Sana2DeviceQuery *)ios2->ios2_StatData;
- size = sdq->SizeAvailable;
- supplied = 0;
- dqi = &DQTable[0];
-
- for(i = 0,w_byte = (UBYTE *)ios2->ios2_StatData; (dqi->Size && (dqi->Size <= size)); i++)
- {
- size -= dqi->Size;
- supplied += dqi->Size;
- dqi = &DQTable[i];
-
- switch(dqi->Type)
- {
- /* Ant of these are constants */
-
- case DQ_CWORD : *(UWORD *)w_byte = dqi->Data;
- w_byte = (UBYTE *)((ULONG)w_byte + 2);
- break;
-
- case DQ_CLONG : *(ULONG *)w_byte = dqi->Data;
- w_byte = (UBYTE *)((ULONG)w_byte + 4);
- break;
-
- /* These two are configuration dependant. */
-
- case DQ_MTU : *(ULONG *)w_byte = slipUnit->su_MTU;
- w_byte = (UBYTE *)((ULONG)w_byte + 4);
- break;
-
- case DQ_BPS : *(ULONG *)w_byte = slipUnit->su_BaudRate;
- w_byte = (UBYTE *)((ULONG)w_byte + 4);
- break;
-
- }
- }
-
- /* I shouldn't have to check this, but I do it anyway for a sanity check. */
- if(sdq->SizeAvailable >= 8)
- {
- sdq->SizeSupplied = supplied;
- }
- TermIO(ios2,slipDevice);
- }
-
- /*
- ** This function is used for handling CMD_WRITE
- ** commands.
- */
- VOID ASM WritePacket(STDSLIPARGS)
- {
- /* Make sure that we are online. */
- if(slipUnit->su_State & SLIPUF_ONLINE)
- {
- /* Make sure it's a legal length. */
- if(ios2->ios2_DataLength <= slipUnit->su_MTU)
- {
- /* Queue the request for the slip.device process. */
-
- ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
-
- PutMsg(slipUnit->su_Tx,(struct Message *)ios2);
-
- }
- else
- {
- /* Sorry, the packet is too long! */
- ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- TermIO(ios2,slipDevice);
- DoEvent(S2EVENT_TX,slipUnit,slipDevice);
- }
- }
- else
- {
- /* Sorry, we're offline */
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2,slipDevice);
- }
- }
-
- VOID ASM SendPacket(STDSLIPARGS)
- {
- struct IOExtSer *ioser;
- struct BufferManagement *bm;
- ULONG framelength;
- UBYTE *hdr;
- u_char ptype;
-
- bm =(struct BufferManagement *) ios2->ios2_BufferManagement;
-
- /* Copy the data out of the packet into our temporary buffer. */
- if((*bm->bm_CopyFromBuffer)(slipUnit->su_TxBuff,ios2->ios2_Data,ios2->ios2_DataLength))
- {
- PacketSent(ios2->ios2_DataLength,slipUnit);
-
- /* See if this packet is TCP and we are allowed to compress packets. */
-
- if((((struct ip *)slipUnit->su_TxBuff)->ip_p == IPPROTO_TCP) &&
- (slipUnit->su_State & SLIPUF_MAYCOMPRESS))
- {
- slipUnit->su_MBuff.m_off = slipUnit->su_TxBuff;
- slipUnit->su_MBuff.m_len = ios2->ios2_DataLength;
- ptype = sl_compress_tcp(&slipUnit->su_MBuff,(struct ip *)slipUnit->su_TxBuff,&slipUnit->su_SLCompress, 1);
- if(ptype == 0x40)
- {
- framelength=EncodeSLIP(slipUnit->su_TxBuff,slipUnit->su_TxSLIP,ios2->ios2_DataLength);
- }
- else
- {
- hdr = slipUnit->su_MBuff.m_off;
- hdr[0] |= ptype;
- framelength=EncodeSLIP(slipUnit->su_MBuff.m_off,slipUnit->su_TxSLIP,slipUnit->su_MBuff.m_len);
- }
- }
-
- /* Either the packet isn't TCP or we're not allowed to use compression */
- else
- {
- /* Encode the packet in SLIP format */
- framelength=EncodeSLIP(slipUnit->su_TxBuff,slipUnit->su_TxSLIP,ios2->ios2_DataLength);
- }
- ioser = slipUnit->su_SerTx;
- ioser->IOSer.io_Data = slipUnit->su_TxSLIP;
- ioser->IOSer.io_Length = framelength;
- ioser->IOSer.io_Command = CMD_WRITE;
- ioser->IOSer.io_Error = 0;
- ioser->IOSer.io_Message.mn_Node.ln_Type = 0;
-
- /* Send the packet to the serial device driver */
- SendIO((struct IORequest *)ioser);
- }
- else
- {
- /* Something went wrong...*/
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_BUFF_ERROR;
- DoEvent(S2EVENT_BUFF,slipUnit,slipDevice);
- }
- TermIO(ios2,slipDevice);
- }
-
- /*
- ** This routine encodes a packet in SLIP format.
- **
- ** The format is quite simple.
- **
- ** SLIP Encoding:
- **
- ** SLIP_ESC -> SLIP_ESC SLIP_ESC_ESC
- ** SLIP_END -> SLIP_ESC SLIP_ESC_END
- **
- ** The packet is preceded and terminated with a SLIP_END as prescribed by
- ** rfc 1055.
- **
- */
- ULONG EncodeSLIP(UBYTE *source, UBYTE *dest, ULONG length)
- {
- UBYTE ch;
- UBYTE *current;
-
- current = dest;
-
- *current = SLIP_END;
- current++;
-
- while(length--)
- {
- ch = *source;
- source++;
-
- if(ch == SLIP_ESC)
- {
- *current = SLIP_ESC;
- current++;
- ch = SLIP_ESC_ESC;
- }
- else if(ch == SLIP_END)
- {
- *current = SLIP_ESC;
- current ++;
- ch = SLIP_ESC_END;
- }
- *current = ch;
- current++;
- }
- *current = SLIP_END;
- current++;
-
- return((ULONG)(current - dest));
- }
-
- /*
- ** This routine handles CMD_READ commands. We
- ** always queue these unless we're offline.
- */
- VOID ASM ReadPacket(STDSLIPARGS)
- {
- struct BufferManagement *bm;
-
- if(slipUnit->su_State & SLIPUF_ONLINE)
- {
- /* Find the appropriate queue for this IO request */
-
- ObtainSemaphore(&slipUnit->su_ListLock);
- bm = (struct BufferManagement *)slipUnit->su_BuffMgmt.mlh_Head;
- while(bm->bm_Node.mln_Succ)
- {
- if(bm == (struct BufferManagement *)ios2->ios2_BufferManagement)
- {
- AddTail((struct List *)&bm->bm_RxQueue,(struct Node *)ios2);
- break;
- }
- bm = (struct BufferManagement *)bm->bm_Node.mln_Succ;
- }
- /* Did we fall of the end of the list? */
- if(!bm->bm_Node.mln_Succ)
- {
- ios2->ios2_Req.io_Error = S2ERR_BAD_ARGUMENT;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- TermIO(ios2,slipDevice);
- }
- ReleaseSemaphore(&slipUnit->su_ListLock);
- }
- else
- {
- /* Sorry, we're offline */
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2,slipDevice);
- }
- }
-
- /*
- ** This routine initializes our IO requests and buffers
- ** for serial i/o and SLIP encoding/decoding.
- */
- BOOL InitSerial(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- ULONG *clr;
- BOOL status = FALSE;
-
- for(clr = (ULONG *) &slipUnit->su_SerRx; clr <= (ULONG *) &slipUnit->su_TxSLIP; clr++)
- *clr = 0L;
-
- if(slipUnit->su_TxPort = CreateMsgPort())
- {
- if(slipUnit->su_SerTx = CreateIORequest(slipUnit->su_TxPort,sizeof(struct IOExtSer)))
- {
- if(slipUnit->su_RxPort = CreateMsgPort())
- {
- if(slipUnit->su_SerRx = CreateIORequest(slipUnit->su_RxPort,sizeof(struct IOExtSer)))
- {
- if(slipUnit->su_TxBuff = AllocMem((slipUnit->su_MTU + 128) * 2,MEMF_CLEAR|MEMF_PUBLIC))
- {
- slipUnit->su_RxBuff = slipUnit->su_TxBuff + slipUnit->su_MTU + 128;
- slipUnit->su_RxBuffPtr = slipUnit->su_RxBuff + 128;
-
- if(slipUnit->su_TxSLIP = AllocMem((slipUnit->su_MTU*2 + 128) * 2,MEMF_CLEAR|MEMF_PUBLIC))
- {
- slipUnit->su_RxSLIP = slipUnit->su_TxSLIP + slipUnit->su_MTU*2 + 128;
- {
- status = TRUE;
- }
- }
- }
- }
- }
- }
- }
- if(!status)
- DeinitSerial(slipUnit,slipDevice);
- return(status);
- }
-
- /*
- ** This routine cleans up our serial i/o requests
- ** and misc. buffers.
- */
- VOID DeinitSerial(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- if(slipUnit->su_SerTx)
- DeleteIORequest(slipUnit->su_SerTx);
-
- if(slipUnit->su_TxPort)
- DeleteMsgPort(slipUnit->su_TxPort);
-
- if(slipUnit->su_SerRx)
- DeleteIORequest(slipUnit->su_SerRx);
-
- if(slipUnit->su_RxPort)
- DeleteMsgPort(slipUnit->su_RxPort);
-
- if(slipUnit->su_TxBuff)
- FreeMem(slipUnit->su_TxBuff,(slipUnit->su_MTU + 128) * 2);
-
- if(slipUnit->su_TxSLIP)
- FreeMem(slipUnit->su_TxSLIP,(slipUnit->su_MTU*2 + 128) * 2);
- }
-
- /*
- ** This routine handles S2_ONEVNET commands.
- */
- VOID ASM OnEvent(STDSLIPARGS)
- {
-
- /* Two special cases. S2EVENT_ONLINE and S2EVENT_OFFLINE are supposed to
- retun immediately if we are already in the state that they are waiting
- for. */
-
- if( ((ios2->ios2_WireError & S2EVENT_ONLINE) && (slipUnit->su_State & SLIPUF_ONLINE)) ||
- ((ios2->ios2_WireError & S2EVENT_OFFLINE) && (!(slipUnit->su_State & SLIPUF_ONLINE))))
- {
- ios2->ios2_Req.io_Error = 0;
- ios2->ios2_WireError &= (S2EVENT_ONLINE|S2EVENT_OFFLINE);
- TermIO(ios2,slipDevice);
- return;
- }
-
- /* Queue anything else */
-
- ObtainSemaphore(&slipUnit->su_ListLock);
- AddTail((struct List *)&slipUnit->su_Events,(struct Node *)ios2);
- ReleaseSemaphore(&slipUnit->su_ListLock);
- }
-
- /*
- ** This routine opens the serial device driver and attempts to bring
- ** the device online.
- */
- BOOL OpenSerial(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- BOOL status = TRUE;
- ULONG odflags = 0;
- #ifdef OWNDEVUNIT_SUPPORT
- STRPTR oduError;
- #endif
- slipUnit->su_SerRx->IOSer.io_Device = NULL;
-
- sl_compress_init(&slipUnit->su_SLCompress);
-
- #ifdef OWNDEVUNIT_SUPPORT
- if(slipUnit->su_ODUBase)
- {
- oduError = AttemptDevUnit(slipUnit->su_SerDevName, slipUnit->su_SerUnitNum, slipUnit->su_OwnerName, 0L);
-
- if(oduError)
- {
- struct Library *IntuitionBase;
- struct EasyStruct es;
- ULONG args[3];
- STRPTR msg;
- args[0]=(ULONG)slipUnit->su_SerDevName;
- args[1]=(ULONG)slipUnit->su_SerUnitNum;
- args[2]=(ULONG)oduError;
- if (oduError[0] == ODUERR_LEADCHAR[0])
- {
- args[2]++;
- msg = "Error locking %s unit %ld: %s";
- }
- else
- msg = "%s unit %ld already owned by %s.";
-
- if(IntuitionBase = OpenLibrary("intuition.library",37L))
- {
- es.es_StructSize=sizeof(struct EasyStruct);
- es.es_Flags=0;
- es.es_Title="Slip.device";
- es.es_TextFormat=msg;
- es.es_GadgetFormat="Okay";
- EasyRequestArgs(NULL, &es, 0, (APTR)args);
- CloseLibrary(IntuitionBase);
- }
-
- return FALSE;
- }
- }
- #endif
- if(slipUnit->su_State & SLIPUF_7WIRE)
- odflags = SERF_7WIRE;
-
- slipUnit->su_SerTx->io_SerFlags = odflags;
-
- if(!OpenDevice(slipUnit->su_SerDevName,slipUnit->su_SerUnitNum,(struct IORequest *)slipUnit->su_SerTx,odflags))
- {
- /* Set up our serial parameters */
- slipUnit->su_SerRx->IOSer.io_Device = slipUnit->su_SerTx->IOSer.io_Device;
- slipUnit->su_SerRx->IOSer.io_Unit = slipUnit->su_SerTx->IOSer.io_Unit;
-
- slipUnit->su_SerTx->IOSer.io_Command = SDCMD_SETPARAMS;
- slipUnit->su_SerTx->io_Baud = slipUnit->su_BaudRate;
- slipUnit->su_SerTx->io_RBufLen = slipUnit->su_RBufLen;
- slipUnit->su_SerTx->io_ReadLen = 8;
- slipUnit->su_SerTx->io_WriteLen = 8;
- slipUnit->su_SerTx->io_StopBits = 1;
- slipUnit->su_SerTx->io_SerFlags = SERF_XDISABLED|SERF_RAD_BOOGIE;
-
- if(!DoIO((struct IORequest *)slipUnit->su_SerTx))
- {
- /* Assume we're now online */
- slipUnit->su_State |= SLIPUF_ONLINE;
-
- /* If we are running with auto-compression on, clear the
- current value of our COMPRESSION flag. */
-
- if(slipUnit->su_State & SLIPUF_AUTOCOMP)
- slipUnit->su_State &= ~SLIPUF_MAYCOMPRESS;
-
- /* Are we checking for serial detect? */
- if(slipUnit->su_State & SLIPUF_CD)
- {
- slipUnit->su_SerTx->IOSer.io_Command = SDCMD_QUERY;
- if(!DoIO((struct IORequest *)slipUnit->su_SerTx))
- {
- if(slipUnit->su_SerTx->io_Status & (1<<5))
- {
- /* Sorry, no carrier, shut down the serial driver
- and set our state to offline. */
- CloseDevice((struct IORequest *)slipUnit->su_SerTx);
- #ifdef OWNDEVUNIT_SUPPORT
- if (slipUnit->su_ODUBase)
- FreeDevUnit(slipUnit->su_SerDevName, slipUnit->su_SerUnitNum);
- #endif
- slipUnit->su_State &= ~SLIPUF_ONLINE;
- }
- }
- else
- status = FALSE;
- }
- if(status)
- {
- /* Queue up the initial CMD_READ command for the
- serial driver. */
- slipUnit->su_SerRx->IOSer.io_Command = CMD_READ;
- slipUnit->su_SerRx->IOSer.io_Length = 1;
- slipUnit->su_SerRx->IOSer.io_Data = slipUnit->su_RxSLIP;
- SendIO((struct IORequest *)slipUnit->su_SerRx);
- }
- }
- else
- status = FALSE;
-
- if(!status)
- CloseDevice((struct IORequest *)slipUnit->su_SerTx);
- }
- else
- {
- struct Library *IntuitionBase;
- struct EasyStruct es;
- ULONG args[2];
- args[0]=(ULONG)slipUnit->su_SerDevName;
- args[1]=(ULONG)slipUnit->su_SerUnitNum;
- if(IntuitionBase = OpenLibrary("intuition.library",37L))
- {
- es.es_StructSize=sizeof(struct EasyStruct);
- es.es_Flags=0;
- es.es_Title="Slip.device";
- es.es_TextFormat="Couldn't open %s unit %ld.";
- es.es_GadgetFormat="Okay";
- EasyRequestArgs(NULL, &es, 0, (APTR)args);
- CloseLibrary(IntuitionBase);
- }
- status = FALSE;
- }
-
- if(slipUnit->su_State & SLIPUF_ONLINE)
- MarkTimeOnline(slipUnit,slipDevice);
-
- #ifdef OWNDEVUNIT_SUPPORT
- if(!status && slipUnit->su_ODUBase)
- FreeDevUnit(slipUnit->su_SerDevName, slipUnit->su_SerUnitNum);
- #endif
-
- return(status);
- }
-
- /*
- ** This routine gets the current system time and stores
- ** it in our global statistics structure.
- */
-
- VOID MarkTimeOnline(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- register struct Library *TimerBase;
- struct timerequest *treq;
-
- if(treq = (struct timerequest *)AllocMem(sizeof(struct timerequest),MEMF_PUBLIC|MEMF_CLEAR))
- {
- if(!OpenDevice("timer.device",UNIT_MICROHZ,(struct IORequest *)treq,0L))
- {
- TimerBase = (struct Library *)treq->tr_node.io_Device;
- GetSysTime(&slipUnit->su_Stats.LastStart);
- CloseDevice((struct IORequest *)treq);
- }
- FreeMem(treq,sizeof(struct timerequest));
- }
- }
-
- /*
- ** This routine aborts any pending activity with the serial
- ** device driver and then brings the slip driver offline.
- */
- VOID CloseSerial(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- AbortIO((struct IORequest *)slipUnit->su_SerRx);
- WaitIO((struct IORequest *)slipUnit->su_SerRx);
-
- while(GetMsg(slipUnit->su_RxPort));
-
- AbortIO((struct IORequest *)slipUnit->su_SerTx);
- WaitIO((struct IORequest *)slipUnit->su_SerTx);
-
- while(GetMsg(slipUnit->su_TxPort));
-
- CloseDevice((struct IORequest *)slipUnit->su_SerRx);
- #ifdef OWNDEVUNIT_SUPPORT
- if (slipUnit->su_ODUBase)
- FreeDevUnit(slipUnit->su_SerDevName, slipUnit->su_SerUnitNum);
- #endif
- slipUnit->su_State &= ~SLIPUF_ONLINE;
- }
-
- /*
- ** This routime handles CMD_ONLINE commands.
- */
- VOID ASM Online(STDSLIPARGS)
- {
-
- if(!(slipUnit->su_State & SLIPUF_ONLINE))
- {
- /* We're offline. Try to go online. */
- if(OpenSerial(slipUnit,slipDevice))
- {
- if(slipUnit->su_State & SLIPUF_ONLINE)
- {
- /* In case someone wants to know...*/
- DoEvent(S2EVENT_ONLINE,slipUnit,slipDevice);
- }
- else
- {
- /* Sorry, the attempt to go online failed. */
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- }
- }
- else
- {
- /* A general problem occured. */
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
- }
- }
- TermIO(ios2,slipDevice);
- }
-
- /*
- ** This routine handles CMD_OFFLINE commands.
- */
- VOID ASM Offline(STDSLIPARGS)
- {
- TermIO(ios2,slipDevice);
-
- if(slipUnit->su_State & SLIPUF_ONLINE)
- {
- /* We're online, so shut everything down. */
- CloseSerial(slipUnit,slipDevice);
- DoOffline(slipUnit,slipDevice);
- DoEvent(S2EVENT_OFFLINE,slipUnit,slipDevice);
- }
- }
-
- /*
- ** This routine is called whenever an "important"
- ** SANA-II event occurs.
- */
- VOID DoEvent(ULONG events,
- struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- struct IOSana2Req *ios2;
- struct IOSana2Req *ios2_next;
-
- ObtainSemaphore(&slipUnit->su_ListLock);
-
- ios2 = (struct IOSana2Req *)slipUnit->su_Events.mlh_Head;
-
- while(ios2->ios2_Req.io_Message.mn_Node.ln_Succ)
- {
- ios2_next = (struct IOSana2Req *)ios2->ios2_Req.io_Message.mn_Node.ln_Succ;
-
- /* Are they waiting for any of these events? */
- if(ios2->ios2_WireError & events)
- {
- ios2->ios2_Req.io_Error = 0;
- ios2->ios2_WireError = events;
- Remove((struct Node *)ios2);
- TermIO(ios2,slipDevice);
- }
- ios2 = ios2_next;
- }
- ReleaseSemaphore(&slipUnit->su_ListLock);
- }
-
- /*
- ** This routine is called whenever the device needs to
- ** be taken offline. We return any pending CMD_READ's
- ** or CMD_WRITE's to their senders.
- */
- VOID DoOffline(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- struct IOSana2Req *ios2;
- struct BufferManagement *bm;
- ObtainSemaphore(&slipUnit->su_ListLock);
-
- bm = (struct BufferManagement *)slipUnit->su_BuffMgmt.mlh_Head;
- while(bm->bm_Node.mln_Succ)
- {
- while(ios2 = (struct IOSana2Req *)RemHead((struct List *)&bm->bm_RxQueue))
- {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2,slipDevice);
- }
- bm = (struct BufferManagement *)bm->bm_Node.mln_Succ;
- }
- while(ios2 = (struct IOSana2Req *)GetMsg(slipUnit->su_Tx))
- {
- ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
- ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
- TermIO(ios2,slipDevice);
- }
- ReleaseSemaphore(&slipUnit->su_ListLock);
- }
-
- /*
- ** This routine is called whenever a CMD_WRITE request
- ** has returned from the serial driver.
- */
- VOID ServiceTxPort(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- struct IOSana2Req *ios2;
-
- /* See if our IORequest is busy. If not, check for a pending
- CMD_WRITE request and send it. */
-
- if(CheckIO((struct IORequest *)slipUnit->su_SerTx))
- {
- WaitIO((struct IORequest *)slipUnit->su_SerTx);
- if(ios2 = (struct IOSana2Req *)GetMsg(slipUnit->su_Tx))
- {
- SendPacket(ios2, slipUnit, slipDevice);
- slipUnit->su_Continue = TRUE;
- }
- }
- }
-
- /*
- ** This routine is called whenever a CMD_READ request
- ** returns from the serial driver. It decodes the
- ** packet data and tries to build complete packets.
- */
- VOID DoSerial(struct IOExtSer *ioSer,
- struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- UBYTE *rx_ptr,*packet_ptr;
- UBYTE rx_byte, packet_byte;
- ULONG length,startptr;
-
- startptr = (ULONG)slipUnit->su_RxBuff;
- packet_ptr = slipUnit->su_RxBuffPtr;
- rx_ptr = slipUnit->su_RxSLIP;
-
- length = ioSer->IOSer.io_Actual;
-
- while(length--)
- {
- rx_byte = packet_byte = *rx_ptr;
- rx_ptr++;
-
- /* Handle SLIP packet decoding...*/
- if(slipUnit->su_Escape)
- {
- if(rx_byte == SLIP_ESC_ESC)
- packet_byte = SLIP_ESC;
- else if(rx_byte == SLIP_ESC_END)
- packet_byte = SLIP_END;
- else
- ReceivedGarbage(slipUnit,slipDevice); /* This packet may be hosed */
-
- slipUnit->su_Escape = FALSE;
- }
- else if(rx_byte == SLIP_ESC)
- {
- slipUnit->su_Escape = TRUE;
- continue;
- }
- else if(rx_byte == SLIP_END)
- {
- GotPacket((ULONG)(packet_ptr - startptr) - 128, slipUnit, slipDevice);
- packet_ptr = slipUnit->su_RxBuff + 128;
- continue;
- }
- *packet_ptr = packet_byte;
- packet_ptr++;
-
- if(((ULONG)(packet_ptr - startptr) - 128) > slipUnit->su_MTU)
- {
- packet_ptr = (UBYTE *)(startptr + 128);
- PacketOverrun(slipUnit,slipDevice);
- }
- }
- slipUnit->su_RxBuffPtr = packet_ptr;
-
- /* Queue up another CMD_READ request...*/
- QueueSerRequest(slipUnit,slipDevice);
- }
-
- /*
- ** This routine is called whenever we think we've got
- ** a complete packet to satisfy a CMD_READ request.
- */
- VOID GotPacket(ULONG length,
- struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- struct IOSana2Req *ios2;
- struct BufferManagement *bm;
- struct ip *iphdr;
- UBYTE *hdr;
- UBYTE type;
-
- /* We ignore zero-length packets. These occur
- in between legal SLIP packets due to the
- way SLIP packets are framed. */
-
- if(length)
- {
- PacketReceived(length,slipUnit);
-
- /* Check out what type of packet we have. */
-
- hdr = (UBYTE *)slipUnit->su_RxBuff + 128;
- type = hdr[0];
-
- if(type & 0x80) /* Compressed TCP */
- {
- type = 0x80;
- }
- else
- {
- if(type >= 0x70) /* Uncompressed TCP */
- {
- hdr[0] = type & 0xCF; /* Fix IP header */
- type = 0x70;
- }
- }
- if((type == 0x70) || (type == 0x80)) /* TCP Packet */
- {
- if(slipUnit->su_State & SLIPUF_AUTOCOMP)
- slipUnit->su_State |= SLIPUF_MAYCOMPRESS;
-
- slipUnit->su_MBuff.m_off = hdr;
- slipUnit->su_MBuff.m_len = length;
- length = sl_uncompress_tcp(&slipUnit->su_MBuff.m_off,length,type,&slipUnit->su_SLCompress);
- hdr = slipUnit->su_MBuff.m_off;
- }
- else /* Just a normal SLIP IP Packet */
- {
- hdr = slipUnit->su_RxBuff + 128;
- }
- iphdr = (struct ip *)hdr;
-
- if(length)
- {
- BOOL dropped = TRUE; /* Set to false if at least one protocol stack
- * managed to get the packet. I don't keep
- * individual statistics for each protocol
- * stack. */
-
- ObtainSemaphore(&slipUnit->su_ListLock);
- bm = (struct BufferManagement *)slipUnit->su_BuffMgmt.mlh_Head;
-
- while(bm->bm_Node.mln_Succ)
- {
- if(ios2 = (struct IOSana2Req *)RemHead((struct List *)&bm->bm_RxQueue))
- {
- /* Make the IO request look like it would if they
- * accept the packet. */
-
- ios2->ios2_DataLength = length; /* Length */
- ios2->ios2_PacketType = 2048; /* IP Packet Type */
- *(ULONG *)ios2->ios2_SrcAddr = iphdr->ip_src.s_addr;
- *(ULONG *)ios2->ios2_DstAddr = iphdr->ip_dst.s_addr;
-
- /* If they don't want the packet, go on to the next
- * protocol stack. */
-
- if((*(HOOK_FUNC)bm->bm_PacketFilterHook->h_Entry)(bm->bm_PacketFilterHook,ios2,hdr))
- {
- /* Copy the data into the protocol stack's buffer using its
- supplied callback routine. */
-
- if((*bm->bm_CopyToBuffer)(ios2->ios2_Data,hdr,length))
- {
- dropped = FALSE;
- }
- else
- {
- ios2->ios2_DataLength = 0;
- ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
- ios2->ios2_WireError = S2WERR_BUFF_ERROR;
- DoEvent(S2EVENT_RX|S2EVENT_BUFF,slipUnit,slipDevice);
- }
- TermIO(ios2,slipDevice);
-
- }
- else /* They didn't want it, so put the IOSana2Req back on the list */
- {
- AddHead((struct List *)&bm->bm_RxQueue,(struct Node *)ios2);
- }
- }
- bm = (struct BufferManagement *)bm->bm_Node.mln_Succ;
- }
- ReleaseSemaphore(&slipUnit->su_ListLock);
-
- if(dropped)
- {
- PacketDropped(slipUnit,slipDevice);
- }
- }
- }
- slipUnit->su_Escape = 0;
- }
-
- /*
- ** This routine is called whenever we need to
- ** get more data from the serial port. We first
- ** to a SDCMD_QUERY to see how much data is available,
- ** if any.
- */
- VOID QueueSerRequest(struct SLIPUnit *slipUnit,
- struct SLIPDevice *slipDevice)
- {
- slipUnit->su_SerRx->IOSer.io_Command = SDCMD_QUERY;
- DoIO((struct IORequest *)slipUnit->su_SerRx);
-
- if(slipUnit->su_State & SLIPUF_CD)
- {
- if(slipUnit->su_SerRx->io_Status & (1<<5))
- {
- /* Oops! We've lost carrier. Go offline. */
- CloseSerial(slipUnit,slipDevice);
- DoOffline(slipUnit,slipDevice);
- DoEvent(S2EVENT_OFFLINE,slipUnit,slipDevice);
- return;
- }
- }
- slipUnit->su_SerRx->IOSer.io_Command = CMD_READ;
- slipUnit->su_SerRx->IOSer.io_Data = slipUnit->su_RxSLIP;
- slipUnit->su_SerRx->IOSer.io_Length = min(slipUnit->su_SerRx->IOSer.io_Actual,slipUnit->su_MTU);
-
- /* If the number of bytes available is zero, queue a request
- for one byte. */
- if(!slipUnit->su_SerRx->IOSer.io_Length)
- slipUnit->su_SerRx->IOSer.io_Length = 1;
-
- SendIO((struct IORequest *)slipUnit->su_SerRx);
- }
-
- /*
- ** This is the C entry point for the Unit process.
- ** A6 has been set up by the assembly stub in slip_dev.asm.
- */
-
- VOID ASM DevProcCEntry(REG(a6) struct SLIPDevice *slipDevice)
- {
- struct Process *proc;
- struct SLIPUnit *slipUnit;
- struct IOExtSer *ioser;
- struct StartupMessage *sm;
- struct BufferManagement *bm;
- struct IOSana2Req *ios2;
- ULONG waitmask,signals;
- UBYTE signalbit;
-
- /* Find our Process pointer and wait for our startup
- message to arrive. */
-
- proc = (struct Process *)FindTask(0L);
-
- WaitPort(&proc->pr_MsgPort);
-
- /* Pull the startup message off of our process messageport. */
- sm = (struct StartupMessage *)GetMsg(&proc->pr_MsgPort);
-
- /* Grab our Unit pointer. */
- slipUnit = (struct SLIPUnit *)sm->Unit;
-
- /* Attempt to allocate a signal bit for our Unit MsgPort. */
- signalbit = AllocSignal(-1L);
- if(signalbit != -1)
- {
- /* Set up our Unit's MsgPort. */
- slipUnit->su_Unit.unit_MsgPort.mp_SigBit = signalbit;
- slipUnit->su_Unit.unit_MsgPort.mp_SigTask = (struct Task *)proc;
- slipUnit->su_Unit.unit_MsgPort.mp_Flags = PA_SIGNAL;
-
- /* Initialize our list semaphore */
- InitSemaphore(&slipUnit->su_ListLock);
-
- /* Initialize our linked lists. */
- slipUnit->su_Tx = CreateMsgPort();
-
- /* Initialize the serial stuff. If all goes okay,
- set slipUnit->su_Proc to pointer to our unit process.
- This will let the Unit init code know that were
- are okay. */
-
- if(InitSerial(slipUnit,slipDevice) && slipUnit->su_Tx)
- slipUnit->su_Proc = proc;
- }
-
- /* Reply to our startup message */
- ReplyMsg((struct Message *)sm);
-
- /* Check slipUnit->su_Proc to see if everything went okay up
- above. */
- if(slipUnit->su_Proc)
- {
- waitmask = (1L<<signalbit) | (1L<<slipUnit->su_RxPort->mp_SigBit) |
- (1L<<slipUnit->su_TxPort->mp_SigBit) | (1L<<slipUnit->su_Tx->mp_SigBit)
- | SIGBREAKF_CTRL_F;
-
- /* Loop...*/
-
- while(TRUE)
- {
- signals = Wait(waitmask);
-
- /* Have we been signaled to shut down? */
- if(signals & SIGBREAKF_CTRL_F)
- break;
-
- do
- {
- slipUnit->su_Continue = FALSE;
-
- if(ios2 = (struct IOSana2Req *)GetMsg((struct MsgPort *)slipUnit))
- {
- slipUnit->su_Continue = TRUE;
- PerformIO(ios2,slipDevice);
- }
- if(ioser = (struct IOExtSer *)GetMsg(slipUnit->su_RxPort))
- {
- slipUnit->su_Continue = TRUE;
- if(slipUnit->su_State & SLIPUF_ONLINE)
- {
- DoSerial(ioser, slipUnit, slipDevice);
- }
- }
- if(slipUnit->su_State & SLIPUF_ONLINE)
- {
- ServiceTxPort(slipUnit,slipDevice);
- }
-
- }
- while(slipUnit->su_Continue);
- }
- /* If we're online, we need to shut everything down. */
- if(slipUnit->su_State & SLIPUF_ONLINE)
- {
- CloseSerial(slipUnit,slipDevice);
- FreeSignal(signalbit);
- while(bm = (struct BufferManagement *)RemHead((struct List *)&slipUnit->su_BuffMgmt))
- FreeMem(bm,sizeof(struct BufferManagement));
-
- }
- DeinitSerial(slipUnit,slipDevice);
-
- #ifdef OWNDEVUNIT_SUPPORT
- if (slipUnit->su_ODUBase)
- CloseLibrary(slipUnit->su_ODUBase);
- #endif
- /* Signal the other side we're exiting. Make sure that
- we exit before they wake up by using the same trick
- when replying to Workbench startup messages. */
-
- Forbid();
- Signal((struct Task *)slipUnit->su_Proc,SIGBREAKF_CTRL_F);
- }
- /* Something went wrong in the init code. Drop out. */
- else
- {
- if(signalbit)
- FreeSignal(signalbit);
- }
- }
-
- /* List init routine. */
- VOID NewList(struct List *list)
- {
- list->lh_Head = (struct Node *)&list->lh_Tail;
- list->lh_Tail = NULL;
- list->lh_TailPred = (struct Node *)list;
- }
-